Skip to content

Conversation

kim
Copy link
Contributor

@kim kim commented Aug 7, 2025

Description of Changes

Implements subscribing to durable commits.

The setting works on a per-connection level, and essentially just delays sending transaction updates until the transaction is reported as durable by the database.

For connectionless SQL operations, the setting works per-request. No SQL syntax is provided by this patch to toggle the configuration.

After some deliberation, I opted to obtain the offset when a transaction commits (as opposed to when it starts). This creates some mild inconvenience, because we prevent the transaction from committing until the corresponding subscription updates are enqueued.
The strategy is, however, more correct should we ever support weaker isolation levels, and it is easier to document.

Follow-ups include:

  • Provide SQL syntax (SET synchronous_commit = ON or something)
  • C# and TypeScript SDKs
  • Reference docs?

API and ABI breaking changes

Not breaking, but adds a parameter to the subscribe and sql endpoints.

Expected complexity level and risk

4

To the author's understanding, ordering of outbound messages is not changed by this patch, even if there are messages that don't have a transaction offset (such as error messages). I.e. while waiting for the transaction offset of a message to become durable, no message enqueued after that message will be delivered. This may not be desirable in some cases.

The patch may contain concurrency bugs, e.g. awaiting futures that may never resolve.

Testing

  • Implemented a new test in the module_subscription_actor module
  • Added unit tests for the core logic in ClientConnectionReceiver

It would be desirable to also have integration-level tests, but I'm currently unsure how to write those without being able to control if and when the database reports an offset as durable.

@kim kim changed the title WIP: confirmed reads Confirmed reads Sep 3, 2025
@kim kim marked this pull request as ready for review September 3, 2025 12:24
return;
maybe_message = messages.recv(), if !closed => {
let Some(message) = maybe_message else {
// The message sender was dropped, even though no close
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsure why the send_loop_terminates_when_unordered_closed started to fail with this patch, but the edge case seems legit.

Only thing to consider is whether the closed atomic should be re-checked when entering this branch.

tracing::warn!(
identity = %self.id.identity,
connection_id = %self.id.connection_id,
confirmed_reads = self.config.confirmed_reads,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that a client with confirmed reads turned on has a somewhat higher risk to exceed the capacity.

It's not very likely, because CLIENT_CHANNEL_CAPACITY is such a large number, but is this warning loud enough?

subscriptions.send_client_message(client, message, tx)?;
Ok::<Option<ExecutionMetrics>, anyhow::Error>(metrics)
})
let (tx_offset_sender, tx_offset_receiver) = oneshot::channel();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One-off queries are not really tested anywhere?

@bfops bfops added the release-any To be landed in any release window label Sep 3, 2025
@kim
Copy link
Contributor Author

kim commented Sep 3, 2025

No idea what might be the matter on windows

@kim kim force-pushed the kim/confirmed-reads branch from 9a0b8aa to 7011721 Compare September 4, 2025 14:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release-any To be landed in any release window
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants